home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / spar372.zip / SANA2_FU.C < prev    next >
C/C++ Source or Header  |  1993-12-17  |  26KB  |  865 lines

  1. /*
  2. ** $Source: dh1:network/parnet/Sana2/Sources/sana2_funcs.c,v $
  3. ** $State: Exp $
  4. ** $Revision: 37.2 $
  5. ** $Date: 93/12/17 22:07:45 $
  6. ** $Author: S.A.Pechler $
  7. **
  8. ** Amiga SANA-II Example PARnet device driver.
  9. **
  10. ** SPAR Sana-II functions.
  11. **
  12. ** Based on the Amiga SANA-II Example SLIP device driver code by bj, 
  13. ** which is (C) Copyright 1992 Commodore-Amiga, Inc.
  14. ** the rhslip.device by Olaf Seibert <rhialto@mbfys.kun.nl>, and on
  15. ** the agnet.device code by ppessi <Pekka.Pessi@hut.fi>, which is
  16. ** Copyright (c) 1993 AmiTCP/IP Group,
  17. **                    Helsinki University of Technology, Finland.
  18. **                    All rights reserved.
  19. **
  20. */
  21.  
  22. #include "device_protos.h"
  23.  
  24. /*
  25. **
  26. ** PerformIO
  27. **
  28. ** PerformIO actually dispatches an io request.  It might be called from
  29. ** the Unit process, or directly from BeginIO (thus on the caller's schedule)
  30. */
  31. VOID PerformIO(struct IOSana2Req *ios2)
  32. {
  33.     struct SPARDevUnit *sdu;
  34.  
  35.     sdu = (struct SPARDevUnit *)ios2->ios2_Req.io_Unit; /* get the Unit pointer */
  36.  
  37.     ios2->ios2_Req.io_Error = NULL;  /* no error so far */
  38.  
  39.     switch(ios2->ios2_Req.io_Command)
  40.     {
  41.         case CMD_READ:              ReadPacket(sdu,ios2);
  42.                                     break;
  43.  
  44.         case CMD_WRITE:             debug(("PerformIO: call to CMD_WRITE\n"))
  45.                                     WritePacket(sdu,ios2);
  46.                                     break;
  47.  
  48.         case S2_DEVICEQUERY:        debug(("PerformIO: call to S2_DEVICEQUERY\n"))
  49.                                     DeviceQuery(sdu,ios2);
  50.                                     break;
  51.  
  52.         case S2_GETSTATIONADDRESS:  debug(("PerformIO: call to S2_GETSTATIONADDRESS\n"))
  53.                                     GetStationAddress(sdu,ios2);
  54.                                     break;
  55.  
  56.         case S2_CONFIGINTERFACE:    debug(("PerformIO: call to S2_CONFIGINTERFACE\n"))
  57.                                     ConfigInterface(sdu,ios2);
  58.                                     break;
  59.  
  60.         case S2_BROADCAST:          debug(("PerformIO: call to S2_BROADCAST\n"))
  61.                                     BroadcastPacket(sdu,ios2);
  62.                                     break;
  63.         case S2_ADDMULTICASTADDRESS:
  64.         case S2_DELMULTICASTADDRESS:
  65.         case S2_MULTICAST:          ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  66.                                     ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  67.                                     debug(("PerformIO: call to not supported function\n"))
  68.  
  69.                                     TermIO(ios2);
  70.                                     break;
  71.  
  72.         case S2_TRACKTYPE:          debug(("PerformIO: call to S2_TRACKTYPE\n"))
  73.                                     TrackType(sdu,ios2);
  74.                                     break;
  75.  
  76.         case S2_UNTRACKTYPE:        debug(("PerformIO: call to S2_UNTRACKTYPE\n"))
  77.                                     UnTrackType(sdu,ios2);
  78.                                     break;
  79.  
  80.         case S2_GETTYPESTATS:       debug(("PerformIO: call to S2_GETTYPESTATS\n"))
  81.                                     GetTypeStats(sdu,ios2);
  82.                                     break;
  83.  
  84.         case S2_GETSPECIALSTATS:    debug(("PerformIO: call to S2_GETSPECIALSTATS\n"))
  85.                                     GetSpecialStats(sdu,ios2);
  86.                                     break;
  87.  
  88.         case S2_GETGLOBALSTATS:     debug(("PerformIO: call to S2_GETGLOBALSTATS\n"))
  89.                                     GetGlobalStats(sdu,ios2);
  90.                                     break;
  91.  
  92.         case S2_ONEVENT:            debug(("PerformIO: call to S2_ONEVENT\n"))
  93.                                     OnEvent(sdu,ios2);
  94.                                     break;
  95.  
  96.         case S2_READORPHAN:         debug(("PerformIO: call to S2_READORPHAN\n"))
  97.                                     ReadOrphan(sdu,ios2);
  98.                                     break;
  99.  
  100.         case S2_ONLINE:             debug(("PerformIO: call to S2_ONLINE\n"))
  101.                                     Online(sdu,ios2);
  102.                                     break;
  103.  
  104.         case S2_OFFLINE:            debug(("PerformIO: call to S2_OFFLINE\n"))
  105.                                     Offline(sdu,ios2);
  106.                                     break;
  107.  
  108.         default:                    debug(("PerformIO: call to unknown function\n"))
  109.                                     ios2->ios2_Req.io_Error = IOERR_NOCMD;
  110.                                     TermIO(ios2);
  111.                                     break;
  112.     }
  113. }
  114.  
  115. /*
  116. ** This function returns any device specific statistics that
  117. ** we may have.  Unfortunately, we don't have any SPAR specific
  118. ** statistics.
  119. */
  120. VOID GetSpecialStats(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  121. {
  122.     struct Sana2SpecialStatHeader *stats;
  123.  
  124.     stats = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
  125.  
  126.     stats->RecordCountSupplied = 0;
  127.     TermIO(ios2);
  128. }
  129.  
  130. /*
  131. ** This function returns the global statistics for the
  132. ** spar device.
  133. */
  134. VOID GetGlobalStats(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  135. {
  136.   struct Sana2DeviceStats *stats;
  137.  
  138.   if (stats = (struct Sana2DeviceStats *)ios2->ios2_StatData)
  139.   {
  140.     stats->PacketsReceived      = sdu->sdu_Stats.PacketsReceived;
  141.     stats->PacketsSent          = sdu->sdu_Stats.PacketsSent;
  142.     stats->BadData              = sdu->sdu_Stats.BadData;
  143.     stats->Overruns             = sdu->sdu_Stats.Overruns;
  144.     stats->UnknownTypesReceived = sdu->sdu_Stats.UnknownTypesReceived;
  145.     stats->Reconfigurations     = sdu->sdu_Stats.Reconfigurations;
  146.     stats->LastStart.tv_secs    = sdu->sdu_Stats.LastStart.tv_secs;
  147.     stats->LastStart.tv_micro   = sdu->sdu_Stats.LastStart.tv_micro; /* Rhialto */
  148.  
  149.     ios2->ios2_Req.io_Error = 0;
  150.     ios2->ios2_WireError = 0;
  151.   }
  152.   else
  153.   {
  154.     ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  155.     ios2->ios2_WireError = S2WERR_NULL_POINTER;
  156.   }
  157.   TermIO(ios2);
  158. }
  159.  
  160. /*
  161. ** This function returns statistics for a specific
  162. ** type of packet that is being tracked.
  163. **
  164. */
  165. VOID GetTypeStats(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  166. {
  167.   struct Sana2PacketTypeStats *stats;
  168.   struct SuperS2PTStats *sstats;
  169.  
  170.   if (stats = (struct Sana2PacketTypeStats *)ios2->ios2_StatData)
  171.   {
  172.     ObtainSemaphore(&sdu->sdu_ListLock);
  173.  
  174.     sstats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  175.  
  176.     while(sstats->ss_Node.mln_Succ)
  177.     {
  178.       /* Is this the desired packet type? */
  179.       if(ios2->ios2_PacketType == sstats->ss_PType)
  180.       {
  181.           stats->PacketsSent     = sstats->ss_Stats.PacketsSent;
  182.           stats->PacketsReceived = sstats->ss_Stats.PacketsReceived;
  183.           stats->BytesSent       = sstats->ss_Stats.BytesSent;
  184.           stats->BytesReceived   = sstats->ss_Stats.BytesReceived;
  185.           stats->PacketsDropped  = sstats->ss_Stats.PacketsDropped;
  186.           break;
  187.       }
  188.       sstats = (struct SuperS2PTStats *)sstats->ss_Node.mln_Succ;
  189.     }
  190.     ReleaseSemaphore(&sdu->sdu_ListLock);
  191.     if(!sstats->ss_Node.mln_Succ)
  192.     {
  193.       ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  194.       ios2->ios2_WireError = S2WERR_NOT_TRACKED;
  195.     }
  196.   }
  197.   else
  198.   {
  199.     ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  200.     ios2->ios2_WireError = S2WERR_NULL_POINTER;
  201.   }
  202.   TermIO(ios2);
  203. }
  204.  
  205. /*
  206. ** This function adds a packet type to the list
  207. ** of those that are being tracked.
  208. */
  209. VOID TrackType(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  210. {
  211.     BOOL TypeFound=FALSE;
  212.     struct SuperS2PTStats *stats;
  213.  
  214.     ObtainSemaphore(&sdu->sdu_ListLock);
  215.  
  216.     stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  217.  
  218.     /* Check in the list is this packet is already been tracked */
  219.     while(stats->ss_Node.mln_Succ)
  220.     {
  221.       if(ios2->ios2_PacketType == stats->ss_PType)
  222.       {
  223.         ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  224.         ios2->ios2_WireError = S2WERR_ALREADY_TRACKED;
  225.         TypeFound=TRUE;
  226.         break;
  227.       }
  228.       stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  229.     }
  230.  
  231.  
  232.     if(!TypeFound) /* Type not in list? */
  233.       if(stats = AllocMem(sizeof(struct SuperS2PTStats),MEMF_CLEAR|MEMF_PUBLIC))
  234.       {   /* Add packet type to the list */
  235.           sdu->sdu_TrackP = TRUE;   
  236.           stats->ss_PType = ios2->ios2_PacketType;
  237.  
  238.           debug(("TrackType: Added Type: %04lx.\n",ios2->ios2_PacketType))
  239.  
  240.           AddTail((struct List *)&sdu->sdu_Track,(struct Node *)stats);
  241.       }
  242.     ReleaseSemaphore(&sdu->sdu_ListLock);
  243.  
  244.     TermIO(ios2);
  245. }
  246.  
  247. /*
  248. ** This function removes a packet type from the
  249. ** list of those that are being tracked.
  250. */
  251. VOID UnTrackType(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  252. {
  253.     struct SuperS2PTStats *stats;
  254.     struct SuperS2PTStats *stats_next;
  255.     BOOL TypeFound = FALSE;
  256.  
  257.     ObtainSemaphore(&sdu->sdu_ListLock);
  258.  
  259.     stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  260.  
  261.     while(stats->ss_Node.mln_Succ)
  262.     {
  263.       stats_next = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  264.       if(ios2->ios2_PacketType == stats->ss_PType)
  265.       {
  266.           Remove((struct Node *)stats);
  267.           FreeMem(stats,sizeof(struct SuperS2PTStats));
  268.           TypeFound = TRUE;
  269.           break;
  270.       }
  271.       stats = stats_next;
  272.     }
  273.     if(!TypeFound) /* Type not found in list */
  274.     {
  275.       ios2->ios2_Req.io_Error  = S2ERR_BAD_STATE;
  276.       ios2->ios2_WireError = S2WERR_NOT_TRACKED;
  277.     }
  278.     if(!stats->ss_Node.mln_Succ) /* list is empty    */
  279.         sdu->sdu_TrackP=FALSE;   /* reset track flag  */
  280.     ReleaseSemaphore(&sdu->sdu_ListLock);
  281.  
  282.     TermIO(ios2);
  283. }
  284.  
  285. /*
  286. ** This function is called whenever we receive a packet
  287. ** from the PARnet device driver.
  288. **
  289. */
  290. VOID PacketReceived(struct SPARDevUnit *sdu, ULONG length)
  291. {
  292.     struct SuperS2PTStats *stats;
  293.  
  294.     sdu->sdu_Stats.PacketsReceived++;
  295.  
  296.     /* Packet tracking enabled ? */
  297.     if(sdu->sdu_TrackP)
  298.     {
  299.       stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  300.  
  301.       /* Check if this packet type is on the tracking list */
  302.       while(stats->ss_Node.mln_Succ)
  303.       {
  304.         if( *(UWORD *)(sdu->sdu_RxBuff+SADDR_LEN*2) == stats->ss_PType)
  305.         {
  306.           /* Found entry for this packet type, updating stats */
  307.           stats->ss_Stats.PacketsReceived++;
  308.           stats->ss_Stats.BytesReceived+=length;
  309.           break;
  310.         }
  311.         stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  312.       }
  313.     }
  314. }
  315.  
  316. /*
  317. ** This function is called whenever a packet is
  318. ** sent to the PARnet device driver.
  319. */
  320. VOID PacketSent(struct SPARDevUnit *sdu, ULONG length)
  321. {
  322.     struct SuperS2PTStats *stats;
  323.  
  324.     sdu->sdu_Stats.PacketsSent++;
  325.  
  326.     /* Packet tracking enabled ? */
  327.     if(sdu->sdu_TrackP)
  328.     {
  329.       stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  330.  
  331.       /* Check if this packet type is on the tracking list */
  332.       while(stats->ss_Node.mln_Succ)
  333.       {
  334.  
  335.         if( *(UWORD *)(sdu->sdu_TxBuff+SADDR_LEN*2) == (UWORD)stats->ss_PType)
  336.         {
  337.           /* Found entry for this packet type, updating stats */
  338.  
  339.           debug(("PacketSent: Tracked packet type: %04lx.\n",stats->ss_PType))
  340.  
  341.           stats->ss_Stats.PacketsSent++;
  342.           stats->ss_Stats.BytesSent+=length;
  343.           break;
  344.         }
  345.         stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  346.       }
  347.     }
  348. }
  349.  
  350. /*
  351. ** This function is called whenever a packet that
  352. ** is too large is received.
  353. */
  354. VOID PacketOverrun(struct SPARDevUnit *sdu)
  355. {
  356.     sdu->sdu_Stats.Overruns++;
  357.     DoEvent(sdu, S2EVENT_RX);
  358. }
  359.  
  360. /*
  361. ** This function is called whenever a packet with
  362. ** garbage data is encountered.
  363. */
  364. VOID ReceivedGarbage(struct SPARDevUnit *sdu)
  365. {
  366.     sdu->sdu_Stats.BadData++;
  367.     DoEvent(sdu, S2EVENT_RX);
  368. }
  369.  
  370. /*
  371. ** This function is called whenever a packet
  372. ** is dropped by the SPAR driver.
  373. */
  374. VOID PacketDropped(struct SPARDevUnit *sdu)
  375. {
  376.     struct SuperS2PTStats *stats;
  377.  
  378.     /* Packet tracking enabled ? */
  379.     if(sdu->sdu_TrackP)
  380.     {
  381.       stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  382.  
  383.       /* Check if this packet type is on the tracking list */
  384.       while(stats->ss_Node.mln_Succ)
  385.       {
  386.  
  387.         if( *(UWORD *)(sdu->sdu_TxBuff+SADDR_LEN*2) == (UWORD)stats->ss_PType)
  388.         {
  389.           /* Found entry for this packet type, updating stats */
  390.           stats->ss_Stats.PacketsDropped++;
  391.           break;
  392.         }
  393.         stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  394.       }
  395.     }
  396. }
  397.  
  398. /*
  399. ** This function is called whenever an orphan packet
  400. ** is received (Routine from the agnet device).
  401. */
  402. VOID 
  403. ReceivedOrphan(struct SPARDevUnit *sdu)
  404. {
  405.   sdu->sdu_Stats.UnknownTypesReceived++;
  406. }
  407.  
  408. /*
  409. ** This function is used to locate an IO request in a linked
  410. ** list and abort it if found.
  411. */
  412. LONG AbortReq(struct MinList *minlist, struct IOSana2Req *ios2)
  413. {
  414.     struct Node *node, *next;
  415.     LONG result=IOERR_NOCMD;
  416.  
  417.     node = (struct Node *)minlist->mlh_Head;
  418.  
  419.     while(node->ln_Succ)
  420.     {
  421.       next = node->ln_Succ;
  422.  
  423.       if(node == (struct Node *)ios2)
  424.       {
  425.           Remove((struct Node *)ios2);
  426.           ios2->ios2_Req.io_Error = IOERR_ABORTED;
  427.           TermIO(ios2);
  428.           result = 0;
  429.       }
  430.       node = next;
  431.     }
  432.     return(result);
  433. }
  434.  
  435. /*
  436. ** This function handles S2_CONFIGINTERFACE commands.
  437. */
  438. VOID ConfigInterface(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  439. {
  440.     UBYTE tempaddr;               /* unvalidated hardware address */
  441.  
  442.     /* Note: we may only be configured once. */
  443.     if(!(sdu->sdu_State & SPARUF_CONFIG))
  444.     {
  445.         /* A PARnet network can only handle addresses of 1 octet, so
  446.          * only the last octet of the given ethernet address is used (an
  447.          * ethernetaddress occupies the first 6 bytes in ios2_SrcAddr) */
  448.         tempaddr = ios2->ios2_SrcAddr[0];
  449.  
  450.         debug(("ConfigInterface: Hw.addr. set to :%d (%08lx%04x).\n",(LONG)tempaddr,*(LONG *)ios2->ios2_SrcAddr,*(UWORD *)(ios2->ios2_SrcAddr+4)))
  451.  
  452.         /* check the address before using, take over when it's ok. */
  453.         if ((tempaddr!=0) && (tempaddr!=255))
  454.                   sdu->sdu_StAddr = tempaddr;
  455.         
  456.         sdu->sdu_State |= SPARUF_CONFIG;
  457.  
  458.         if(!(OpenPARnet(sdu)))
  459.         { /* failed to open */
  460.           sdu->sdu_State &= ~SPARUF_CONFIG;
  461.           ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
  462.           ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  463.         }
  464.     }
  465.     else
  466.     {
  467.         /* Sorry, we're already configured. */
  468.         ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  469.         ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
  470.     }
  471.     TermIO(ios2);
  472. }
  473.  
  474.  
  475. /*
  476. ** This function handles S2_BROADCAST commands.
  477. ** It is very limited, because PARnet does not support packet broadcast.
  478. ** Only ARP broadcasts will be accepted and processed internally.
  479. ** 
  480. */
  481. VOID BroadcastPacket(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  482. {
  483.    struct BufferManagement *bm;
  484.    struct ARPframePacket *ARPreqPacket;
  485.    /* ARP response packet */
  486.    struct ARPframePacket ARPrespPacket = {0,0,ETHERTYPE_ARP,ARPHRD_ETHER,ETHERTYPE_IP,6,4,ARPOP_REPLY,0,0,0,0};
  487.  
  488.    if (sdu->sdu_DestAddr)
  489.    { 
  490.      memset(ios2->ios2_DstAddr, 0, SANA2_MAX_ADDR_BYTES); /* Clear dest.addr. */
  491.      ios2->ios2_DstAddr[0]=sdu->sdu_DestAddr; /* fill in destination address */
  492.      WritePacket(sdu,ios2); /* Just write it to the other end */
  493.    }
  494.    else
  495.    {
  496.     bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
  497.  
  498.     /* Copy the data out of the packet into our temporary buffer. */
  499.     if((*bm->bm_CopyFromBuffer)(sdu->sdu_RxBuff+SHDR_LEN,ios2->ios2_Data,ios2->ios2_DataLength))
  500.     {
  501.       ARPreqPacket=(struct ARPframePacket *)sdu->sdu_RxBuff;  /* Pointer to ARP frame  */
  502.  
  503.       if ((UWORD)ios2->ios2_PacketType == ETHERTYPE_ARP)       /* ARP broadcast? */
  504.       {
  505.         debug(("ARP Req (%ld): %08lx%08lx%08lx%08lx%08lx%08lx",ios2->ios2_DataLength,*(LONG *)sdu->sdu_RxBuff,*(LONG *)(sdu->sdu_RxBuff+4),*(LONG *)(sdu->sdu_RxBuff+8),*(LONG *)(sdu->sdu_RxBuff+12),*(LONG *)(sdu->sdu_RxBuff+16),*(LONG *)(sdu->sdu_RxBuff+20)))
  506.  
  507.         ARPrespPacket.ar_dstaddr=sdu->sdu_StAddr; /* frame target h/w address (myself) */
  508.                                                   /* frame type already filled in
  509.                                                    * with ETHERTYPE_ARP as default */
  510.  
  511.         /* copy sender's addresses to target address fields */
  512.         ARPrespPacket.ar_tpa=ARPreqPacket->ar_spa;
  513.         memcpy(&ARPrespPacket.ar_tha,ARPreqPacket->ar_sha,EADDR_LEN);
  514.  
  515.         /* copy target IP address to sender's IP address field */
  516.  
  517.         ARPrespPacket.ar_spa=ARPreqPacket->ar_tpa;
  518.  
  519.         /* calculate the target hardware address from the last octet of the
  520.          * target IP address */
  521.  
  522.         ARPrespPacket.ar_sha[0]=
  523.  
  524.         /* Fill in also hardware source address */
  525.         ARPrespPacket.ar_srcaddr= (UBYTE)ARPrespPacket.ar_spa;
  526.  
  527.         /* copy packet to receiver buffer */
  528.         memcpy(sdu->sdu_RxBuff,&ARPrespPacket,sizeof(ARPrespPacket));
  529.  
  530.         debug(("Tx ARP resp (%ld): %08lx%08lx%08lx%08lx%08lx%08lx",sizeof(ARPrespPacket),*(LONG *)sdu->sdu_RxBuff,*(LONG *)(sdu->sdu_RxBuff+4),*(LONG *)(sdu->sdu_RxBuff+8),*(LONG *)(sdu->sdu_RxBuff+12),*(LONG *)(sdu->sdu_RxBuff+16),*(LONG *)(sdu->sdu_RxBuff+20)))
  531.  
  532.         GotPacket(sdu,sizeof(ARPrespPacket));
  533.       }
  534.       else                  /* non-ARP broadcast packet */
  535.       {
  536.         debug(("Unsupported broadcast packet type\n"))
  537.         PacketDropped(sdu); /* Can't handle address 255 */    
  538.       }
  539.     }
  540.     else
  541.     {
  542.        /* Something went wrong...*/
  543.        ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  544.        ios2->ios2_WireError = S2WERR_BUFF_ERROR;
  545.        DoEvent(sdu,S2EVENT_BUFF);
  546.     }
  547.     TermIO(ios2);
  548.   }
  549. }
  550.  
  551. /*
  552. ** This function handles S2_GETSTATIONADDRESS commands.
  553. **
  554. ** PARnet uses only 1 octet, so only the 1th byte in ios2_SrcAddr will be
  555. ** filled.
  556. **
  557. ** Rhialto: What we want is the config file address as hardware
  558. **        address, and the S2_CONFIGINTERFACE address as current address.
  559. **
  560. */
  561.  
  562. VOID GetStationAddress(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  563. {
  564.     /* Clear address space */
  565.     memset(ios2->ios2_DstAddr, 0, SANA2_MAX_ADDR_BYTES);
  566.     memset(ios2->ios2_SrcAddr, 0, SANA2_MAX_ADDR_BYTES);
  567.  
  568.     /* Place our current address in first position of Src_Addr.
  569.      * And our hardware address (given in spar#.config) in Dst_Addr.
  570.      */
  571.     ios2->ios2_SrcAddr[0]=sdu->sdu_StAddr;
  572.     ios2->ios2_DstAddr[0]=sdu->sdu_HwAddr;
  573.  
  574.     debug(("GetStationAddr: %08lx%04lx.\n",*(LONG *)ios2->ios2_SrcAddr,*(UWORD *)(ios2->ios2_SrcAddr+4)))
  575.  
  576.     TermIO(ios2);
  577. }
  578.  
  579. /*
  580. ** This function handles S2_DEVICEQUERY comands.
  581. */
  582. VOID DeviceQuery(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  583. {
  584.     struct Sana2DeviceQuery *sdq;
  585.  
  586.     sdq = (struct Sana2DeviceQuery *)ios2->ios2_StatData;
  587.  
  588.     sdq->AddrFieldSize = 48;                      /* six bytes (48 bits) hardware address */
  589.                                                   /* this is for Ethernet compatibility, */
  590.                                                   /* Spar uses 1 byte h/w addresses. */
  591.     sdq->MTU = SPAR_MTU;                          /* max. trans. unit */
  592.     sdq->BPS = SPAR_SPEED;                        /* PARnet has fixed speed */
  593.     sdq->HardwareType = S2WireType_Ethernet;      /* fake! */
  594.  
  595.     sdq->DevQueryFormat = NULL;
  596.     sdq->DeviceLevel    = NULL;
  597.     sdq->SizeSupplied   = sizeof(struct Sana2DeviceQuery);
  598.     TermIO(ios2);
  599. }
  600.  
  601. /*
  602. ** This function is used for handling CMD_WRITE
  603. ** commands.
  604. */
  605. VOID WritePacket(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  606. {
  607.  
  608.     /* Make sure that we are online. */
  609.     if(sdu->sdu_State & SPARUF_ONLINE)
  610.     {
  611.       /* Make sure it's a legal length. */
  612.       if(ios2->ios2_DataLength <= SPAR_MTU)
  613.       {
  614.           /* See if our PARnet CMD_WRITE command is busy.  If it's not, send
  615.            * the IO request to SendPacket. */
  616.           if(CheckIO((struct IORequest *)sdu->sdu_ParTx))
  617.           {
  618.             WaitIO((struct IORequest *)sdu->sdu_ParTx);
  619.             SendPacket(sdu, ios2);
  620.           }
  621.           else
  622.           {
  623.             /* We'll have to queue the packet for later...*/
  624.             ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
  625.             ObtainSemaphore(&sdu->sdu_ListLock);
  626.             AddTail((struct List *)&sdu->sdu_Tx,(struct Node *)ios2);
  627.             ReleaseSemaphore(&sdu->sdu_ListLock);
  628.           }
  629.       }
  630.       else
  631.       {
  632.           /* Sorry, the packet is too long! */
  633.           ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
  634.           ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  635.           TermIO(ios2);
  636.           DoEvent(sdu,S2EVENT_TX);
  637.       }
  638.     }
  639.     else
  640.     {
  641.       /* Sorry, we're offline */
  642.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  643.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  644.       TermIO(ios2);
  645.     }
  646. }
  647.  
  648. /*
  649. ** This routine handles CMD_READ commands.  We
  650. ** always queue these unless we're offline.
  651. */
  652. VOID ReadPacket(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  653. {
  654.  
  655.     if(sdu->sdu_State & SPARUF_ONLINE)
  656.     {
  657.       /* Queue it... */
  658.       ObtainSemaphore(&sdu->sdu_ListLock);
  659.       AddTail((struct List *)&sdu->sdu_Rx,(struct Node *)ios2);
  660.       ReleaseSemaphore(&sdu->sdu_ListLock);
  661.     }
  662.     else
  663.     {
  664.       /* Sorry, we're offline */
  665.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  666.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  667.       TermIO(ios2);
  668.     }
  669. }
  670.  
  671. /*
  672. ** This routine handles CMD_READORPHAN commands.  We
  673. ** always queue these unless we're offline.
  674. **
  675. */
  676. VOID ReadOrphan(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  677. {
  678.  
  679.     if(sdu->sdu_State & SPARUF_ONLINE)
  680.     {
  681.       /* Queue it...*/
  682.       ObtainSemaphore(&sdu->sdu_ListLock);
  683.       AddTail((struct List *)&sdu->sdu_RxOrph,(struct Node *)ios2);
  684.       ReleaseSemaphore(&sdu->sdu_ListLock);
  685.     }
  686.     else
  687.     {
  688.       /* Sorry, we're offline */
  689.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  690.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  691.       TermIO(ios2);
  692.     }
  693. }
  694.  
  695. /*
  696. ** This routine handles S2_ONEVENT commands.
  697. */
  698. VOID OnEvent(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  699. {
  700.  
  701.     switch(ios2->ios2_WireError)
  702.     {
  703.       /* Special case.  We may already be online, in which
  704.        * case the IO request should return immediately. Otherwise
  705.        * we queue it for later. */
  706.  
  707.       case S2EVENT_ONLINE:
  708.             if(sdu->sdu_State & SPARUF_ONLINE)
  709.                 TermIO(ios2);
  710.             else
  711.             {
  712.                 ObtainSemaphore(&sdu->sdu_ListLock);
  713.                 AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
  714.                 ReleaseSemaphore(&sdu->sdu_ListLock);
  715.             }
  716.             break;
  717.  
  718.       /* Same as with S2EVENT_ONLINE, but the opposite
  719.        * happens. */
  720.       case S2EVENT_OFFLINE:
  721.         if(sdu->sdu_State & SPARUF_ONLINE)
  722.         {
  723.             ObtainSemaphore(&sdu->sdu_ListLock);
  724.             AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
  725.             ReleaseSemaphore(&sdu->sdu_ListLock);
  726.         }
  727.         else
  728.             TermIO(ios2);
  729.         break;
  730.  
  731.       /* Just queue everything else. */
  732.       default:
  733.             ObtainSemaphore(&sdu->sdu_ListLock);
  734.             AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
  735.             ReleaseSemaphore(&sdu->sdu_ListLock);
  736.             break;
  737.     }
  738. }
  739.  
  740. /*
  741. ** This routine gets the current system time and stores
  742. ** it in our global statistics structure.
  743. */
  744.  
  745. VOID MarkTimeOnline(struct SPARDevUnit *sdu)
  746. {
  747.     register struct Library *TimerBase;
  748.     struct timerequest *treq;
  749.  
  750.     if(treq = (struct timerequest *)AllocMem(sizeof(struct timerequest),MEMF_PUBLIC|MEMF_CLEAR))
  751.     {
  752.       if(!OpenDevice("timer.device",UNIT_MICROHZ,(struct IORequest *)treq,NULL))
  753.       {
  754.           TimerBase = (struct Library *)treq->tr_node.io_Device;
  755.           GetSysTime(&sdu->sdu_Stats.LastStart);
  756.           CloseDevice((struct IORequest *)treq);
  757.       }
  758.       FreeMem(treq,sizeof(struct timerequest));
  759.     }
  760. }
  761.  
  762. /*
  763. ** This routine handles CMD_ONLINE commands.
  764. */
  765. VOID Online(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  766. {
  767.  
  768.     if(!(sdu->sdu_State & SPARUF_ONLINE))
  769.     {
  770.       /* We're offline. Try to go online. */
  771.       if(OpenPARnet(sdu))
  772.       {
  773.           if(sdu->sdu_State & SPARUF_ONLINE)
  774.           {
  775.             /* In case someone wants to know...*/
  776.             DoEvent(sdu, S2EVENT_ONLINE);
  777.           }
  778.           else
  779.           {
  780.             /* Sorry, the attempt to go online failed. */
  781.             ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  782.             ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  783.           }
  784.         }
  785.         else
  786.         {
  787.             /* A general problem occured. */
  788.             ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  789.             ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  790.         }
  791.     }
  792.     TermIO(ios2);
  793. }
  794.  
  795. /*
  796. ** This routine handles CMD_OFFLINE commands.
  797. */
  798. VOID Offline(struct SPARDevUnit *sdu, struct IOSana2Req *ios2)
  799. {
  800.     TermIO(ios2);
  801.  
  802.     if(sdu->sdu_State & SPARUF_ONLINE)
  803.     {
  804.       /* We're online, so shut everything down. */
  805.       ClosePARnet(sdu);
  806.       DoOffline(sdu);
  807.       DoEvent(sdu,S2EVENT_OFFLINE);
  808.     }
  809. }
  810.  
  811. /*
  812. ** This routine is called whenever an "important"
  813. ** SANA-II event occurs.
  814. */
  815. VOID DoEvent(struct SPARDevUnit *sdu, ULONG event)
  816. {
  817.     struct IOSana2Req *ios2;
  818.     struct IOSana2Req *ios2_next;
  819.  
  820.     ObtainSemaphore(&sdu->sdu_ListLock);
  821.  
  822.     ios2 = (struct IOSana2Req *)sdu->sdu_Events.mlh_Head;
  823.  
  824.     while(ios2->ios2_Req.io_Message.mn_Node.ln_Succ)
  825.     {
  826.       ios2_next = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
  827.  
  828.       /* Is this the event they are looking for? */
  829.       if(ios2->ios2_WireError == event)
  830.       {
  831.           Remove((struct Node *)ios2);
  832.           TermIO(ios2);
  833.       }
  834.       ios2 = ios2_next;
  835.     }
  836.     ReleaseSemaphore(&sdu->sdu_ListLock);
  837. }
  838.  
  839. /*
  840. ** This routine is called whenever the device needs to
  841. ** be taken offline.  We return any pending CMD_READ's
  842. ** or CMD_WRITE's to their senders.
  843. */
  844. VOID DoOffline(struct SPARDevUnit *sdu)
  845. {
  846.     struct IOSana2Req *ios2;
  847.  
  848.     ObtainSemaphore(&sdu->sdu_ListLock);
  849.  
  850.     while(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Rx))
  851.     {
  852.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  853.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  854.       TermIO(ios2);
  855.     }
  856.  
  857.     while(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Tx))
  858.     {
  859.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  860.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  861.       TermIO(ios2);
  862.     }
  863.     ReleaseSemaphore(&sdu->sdu_ListLock);
  864. }
  865.